package sdk

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"net/url"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"time"
)

func generateSignature(params url.Values, appSecret string) (signature string) {
	filteredParams := make(url.Values)
	for key, values := range params {
		if key != "sign" {
			filteredParams[key] = values
		}
	}
	keys := make([]string, 0, len(filteredParams))
	for key := range filteredParams {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	var strToSign strings.Builder
	for i, key := range keys {
		if i > 0 {
			strToSign.WriteString("&")
		}
		strToSign.WriteString(fmt.Sprintf("%s=%s", key, filteredParams.Get(key)))
	}
	h := hmac.New(sha256.New, []byte(appSecret))
	h.Write([]byte(strToSign.String()))
	signature = hex.EncodeToString(h.Sum(nil))
	return
}

func extractParams(method string, queryParams url.Values, bodyParams interface{}) url.Values {
	params := make(url.Values)
	for key, values := range queryParams {
		if len(values) > 0 && strings.TrimSpace(values[0]) != "" {
			params[key] = values
		}
	}
	if method == "POST" || method == "PUT" || method == "PATCH" || method == "DELETE" {
		switch body := bodyParams.(type) {
		case url.Values:
			for key, values := range body {
				if len(values) > 0 && strings.TrimSpace(values[0]) != "" {
					params[key] = values
				}
			}
		case map[string]interface{}:
			for key, value := range body {
				vType := reflect.TypeOf(value)
				switch vType.Kind() {
				case reflect.Array, reflect.Slice:
					elemType := vType.Elem()
					switch elemType.Kind() {
					case reflect.Int:
						vv := value.([]int)
						var strSlice []string
						for _, value := range vv {
							strSlice = append(strSlice, strconv.Itoa(value))
						}
						params.Set(key, strings.Join(strSlice, ","))
					default:
						vv := value.([]string)
						params.Set(key, strings.Join(vv, ","))
					}
				case reflect.String:
					vv := value.(string)
					if strings.TrimSpace(vv) != "" {
						params.Set(key, fmt.Sprintf("%v", value))
					}
				default:
					params.Set(key, fmt.Sprintf("%v", value))
				}

			}
		default:
			panic("不支持的请求体格式")
		}
	}
	return params
}

func (c *client) buildGetParam(in url.Values) url.Values {
	timestamp := time.Now().Unix()
	in.Add("app_id", c.appId)
	in.Add("timestamp", strconv.FormatInt(timestamp, 10))
	in.Add("sign", generateSignature(extractParams("GET", in, in), c.appSecret))
	return in
}

func (c *client) buildPostParam(in map[string]any) map[string]any {
	timestamp := time.Now().Unix()
	in["app_id"] = c.appId
	in["timestamp"] = timestamp
	in["sign"] = generateSignature(extractParams("POST", nil, in), c.appSecret)
	return in
}
